package com.jz.pay.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.jz.commom.api.dto.request.Payment;
import com.jz.commom.api.dto.response.CommonResult;
import com.jz.pay.bo.RedisTemplateBO;
import com.jz.pay.bo.RocketMQBO;
import com.jz.pay.consumer.TopicType;
import com.jz.pay.factories.FactoryManager;
import com.jz.pay.factories.dto.WrapperDTO;
import com.jz.pay.factories.tmp.OnethingProcess;
import com.jz.pay.pool.MyThreadPool;
import com.jz.pay.service.PaymentService;
import com.jz.pay.utils.lock.Lock;
import com.jz.pay.utils.lock.RedisLock;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQLocalRequestCallback;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
//import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ObjectUtils;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

@RestController
@Slf4j
@Api
@ApiModel(value = "支付接口")
public class PaymentController {
    @Resource
    private PaymentService paymentService;

    private PaymentService paymentService2;

    public PaymentService getPaymentService() {
        return paymentService;
    }

    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public PaymentService getPaymentService2() {
        return paymentService2;
    }

    public void setPaymentService2(PaymentService paymentService2) {
        this.paymentService2 = paymentService2;
    }

    @ApiOperation(value = "创建订单")
    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment){
        int result = paymentService.create(payment);
        log.info("*** 插入结果："+result);
        if(result>0){
            return CommonResult.success("ok","");
        }else{
            return CommonResult.fail("插入失败","");
        }
    }

    /**
     * 分表后创建
     * @param payment
     * @return
     */
    @ApiOperation(value = "创建订单")
    @PostMapping(value = "/payment/createNew")
    public CommonResult createNew(@RequestBody Payment payment){
        int result = paymentService.createNew(payment);
        log.info("*** 插入结果："+result);
        if(result>0){
            return CommonResult.success("ok","");
        }else{
            return CommonResult.fail("插入失败","");
        }
    }

    /**
     * 分表后创建
     * @param payment
     * @return
     */
    @ApiOperation(value = "创建订单")
    @PostMapping(value = "/payment/query")
    public CommonResult query(@RequestBody Payment payment){
        List<Payment> result= paymentService.query(payment);
        log.info("*** 查询结果："+result);
        if(result.size()<=0){
            return CommonResult.fail("查询无对应数据",null);
        }else{
            return CommonResult.success(result);
        }
    }

    @ApiOperation(value = "创建订单")
    @RequestMapping(value = "/payment/testRestApi",method = RequestMethod.GET)
    public void testRestApi(@RequestBody Payment payment){

    }
    @ApiOperation(value = "创建订单")
    @RequestMapping(value = "/payment/testRestApi",method = RequestMethod.POST)
    public void testRestApi2(@RequestBody Payment payment){

    }

    @ApiOperation(value = "根据ID查询订单")
    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
        Payment result = paymentService.getPaymentById(id);
        log.info("*** 查询结果："+result);
        if(ObjectUtils.isEmpty(result)){
            return CommonResult.fail("查询无对应数据",null);
        }else{
            return CommonResult.success(result);
        }
    }


    /**
     * testSentinel
     * @return CommonResult
     */
    @ApiOperation(value = "testSentinel")
    @GetMapping(value = "/payment/testSentinel")
    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult testSentinel(){
        return CommonResult.success("ok","");
    }

    public CommonResult sentinelHandler(BlockException ex){
        System.out.println("流量异常！！！！！！");
        System.out.println(ex.getMessage());
        return CommonResult.success("失败拉！！！！！！！","");
    }

    @Resource
    FactoryManager factoryManager;
    @ApiOperation(value = "testFactory")
    @GetMapping(value = "/payment/testFactory/{id}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult testFactory(@PathVariable("id")  String id){
        WrapperDTO dto  = factoryManager.getFactory(id).getInstance(id);
        OnethingProcess onethingProcess = factoryManager.getOnethingProcess(dto);
        onethingProcess.invoke(dto);
        return CommonResult.success("ok","");
    }


    @Resource
    RocketMQBO rocketMQBO;

    @ApiOperation(value = "sendMsg")
    @GetMapping(value = "/payment/sendMsg/{topic}/{key}/{msg}")
    public CommonResult sendMsg(@PathVariable("topic")  String topic,@PathVariable("key")  String key,@PathVariable("msg")  String msg){
        System.out.println("----------------------------");
        System.out.println("消息接收："+msg);
        HashMap<String,String> map = new HashMap<>();
        map.put(RocketMQHeaders.KEYS,key);
        map.put(RocketMQHeaders.TAGS,"mytag");
        rocketMQBO.send(topic, msg,map);
        return CommonResult.success("ok",msg);
    }

    @ApiOperation(value = "sendMessageCallback")
    @GetMapping(value = "/payment/sendMessageCallback/{topic}/{key}/{msg}")
    public CommonResult sendMessageCallback(@PathVariable("topic")  String topic,@PathVariable("key")  String key,@PathVariable("msg")  String msg){
        System.out.println("----------------------------");
        System.out.println("消息接收："+msg);
        HashMap<String,String> map = new HashMap<>();
        map.put(RocketMQHeaders.KEYS,key);
        map.put(RocketMQHeaders.TAGS,"mytag");
        rocketMQBO.sendMessageCallback(topic, msg,map,new RocketMQLocalRequestCallback() {
            @Override
            public void onSuccess(Object o) {
                System.out.println("onSuccess");
                System.out.println(o);
            }

            @Override
            public void onException(Throwable throwable) {
                System.out.println("onException");
                System.out.println(throwable);
                throwable.printStackTrace();
            }
        });
        return CommonResult.success("ok",msg);
    }

    @ApiOperation(value = "asyncSend")
    @GetMapping(value = "/payment/asyncSend/{topic}/{key}/{msg}")
    public CommonResult asyncSend(@PathVariable("topic")  String topic,@PathVariable("key")  String key,@PathVariable("msg")  String msg){
        System.out.println("----------------------------");
        System.out.println("消息接收："+msg);
        HashMap<String,String> map = new HashMap<>();
        map.put(RocketMQHeaders.KEYS,key);
        map.put(RocketMQHeaders.TAGS,"mytag");
        rocketMQBO.asyncSend(topic, msg, map,new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                if (sendResult.getSendStatus().equals(SendStatus.SEND_OK)){
                    System.out.println("onSuccess");
                    System.out.println(sendResult);
                }
            }

            @Override
            public void onException(Throwable throwable) {
                System.out.println("onException");
                throwable.printStackTrace();
            }
        });
        return CommonResult.success("ok",msg);
    }

    @ApiOperation(value = "asyncSendBatch")
    @GetMapping(value = "/payment/asyncSendBatch/{topic}/{key}/{msg}")
    public CommonResult asyncSendBatch(@PathVariable("topic")  String topic,@PathVariable("key")  String key,@PathVariable("msg")  String msg){
        System.out.println("----------------------------");
        System.out.println("消息接收："+msg);
        HashMap<String,String> map = new HashMap<>();
        map.put(RocketMQHeaders.KEYS,key);
        map.put(RocketMQHeaders.TAGS,"mytag");
        SendResult result = rocketMQBO.asyncSendBatch(topic, Arrays.asList(msg.split(",")), map);
        System.out.println(result);
        return CommonResult.success("ok",msg);
    }

    @Resource
    RedisTemplateBO redisTemplateBO;

    /**
     * 单线程操作
     * @param key
     * @param value
     * @return
     */
    @ApiOperation(value = "sendLua")
    @GetMapping(value = "/payment/sendLua/{key}/{value}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult sendLua(@PathVariable("key")  String key,@PathVariable("value")  String value){
        redisTemplateBO.hashIncre(key,value);
        return CommonResult.success("ok",value);
    }

    /**
     * 创建新线程执行
     * @param key
     * @param value
     * @param ts
     * @return
     */
    @ApiOperation(value = "sendLuaThread")
    @GetMapping(value = "/payment/sendLuaThread/{key}/{value}/{ts}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult sendLuaThread(@PathVariable("key") String key,@PathVariable("value") String value,@PathVariable("ts") int ts){
        long t = System.currentTimeMillis();
        System.out.println();
        for (int i = 0; i < ts; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    redisTemplateBO.hashIncre(key,value);
                    long e = System.currentTimeMillis();
                    System.out.println(t+","+e+" "+(e-t));
                }
            }).start();
        }
        return CommonResult.success("ok",value);
    }

    /**
     * 适用线程池并发操作
     * @param key
     * @param value
     * @param ts
     * @return
     */
    @ApiOperation(value = "sendThread")
    @GetMapping(value = "/payment/sendThread/{key}/{value}/{ts}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult sendThread(@PathVariable("key") String key,@PathVariable("value") String value,@PathVariable("ts") int ts){
        long t = System.currentTimeMillis();
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setThreadFactory(new CustomizableThreadFactory(){
            public Thread newThread(Runnable runnable) {
                Thread t = this.createThread(runnable);
                t.setName(t.getName()+"-sendThread");
                return t;
            }
        });
        pool.setCorePoolSize(16);
        pool.initialize();
        for (int i = 0; i < ts; i++) {
            pool.execute(new Runnable() {
                @Override
                public void run() {
                    redisTemplateBO.hashIncre(key,value);
                    long e = System.currentTimeMillis();
                    System.out.println(t+","+e+" "+(e-t));
                }
            });
        }
        return CommonResult.success("ok",value);
    }

    MyThreadPool pool;

    /**
     * 适用线程池并发操作
     * @param key
     * @param value
     * @param ts
     * @return
     */
    @ApiOperation(value = "sendMyThread")
    @GetMapping(value = "/payment/sendMyThread/{key}/{value}/{ts}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult sendMyThread(@PathVariable("key") String key,@PathVariable("value") String value,@PathVariable("ts") int ts){
        if(this.pool == null){
           this.pool = new MyThreadPool(17,17);
        }
        long t = System.currentTimeMillis();
        for (int i = 0; i < ts; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    redisTemplateBO.hashIncre(key,value);
                    long e = System.currentTimeMillis();
                    System.out.println(t+","+e+" "+(e-t));
                }
            });
        }
        return CommonResult.success("ok",value);
    }



    /**
     * 适用线程池并发操作
     * @param key
     * @param value
     * @return
     */
    @ApiOperation(value = "getLock")
    @GetMapping(value = "/payment/getLock/{key}/{value}")
//    @SentinelResource(value="my_resource",blockHandler="sentinelHandler")
    public CommonResult getLock(@PathVariable("key") String key,@PathVariable("value") String value){
        RedisLock redisLock = null;
        try {
            redisLock = RedisLock.lock(key);
            //
            // 执行任务或业务
            //
            System.out.println("业务执行完毕");
        }catch (RuntimeException e){
            return CommonResult.success(e.getMessage(),value);
        } finally {
            if(redisLock != null){
                redisLock.unlock();
            }
        }
        return CommonResult.success("ok",value);
    }

}
